package com.thiswhyme.storage.core.platform;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.*;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import com.thiswhyme.common.conststant.CommonConstant;
import com.thiswhyme.common.expection.BusinessException;
import com.thiswhyme.common.response.ResponseCode;
import com.thiswhyme.storage.core.FileStorage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.function.Consumer;

/**
 * @description: 七牛云对象存储服务
 * @author: thiswhyme
 * @date: 2021/6/29
 */
@Slf4j
@AllArgsConstructor
public class QiniuKodoStorage implements FileStorage {

    private String configKey;
    private String accessKey;
    private String secretKey;
    private String bucketName;
    private String domain;

    private QiniuKodoStorage() {

    }

    public Auth getAuth() {
        return Auth.create(accessKey, secretKey);
    }

    public BucketManager getBucketManager() {
        return new BucketManager(getAuth(), new Configuration(Region.autoRegion()));
    }

    public UploadManager getUploadManager() {
        return new UploadManager(new Configuration(Region.autoRegion()));
    }

    @Override
    public String platformCode() {
        return PlatformType.KODO.name() + CommonConstant.HYPHEN + configKey;
    }

    @Override
    public String upload(InputStream inputStream, String keyName) {
        try {
            StringMap putPolicy = new StringMap();
            //设置回调URL
            //putPolicy.put("callbackUrl", "http://api.example.com/qiniu/upload/callback");
            //指定返回body结构
            putPolicy.put("returnBody", "{\"key\":\"$(key)\",\"hash\":\"$(etag)\",\"bucket\":\"$(bucket)\",\"fsize\":$(fsize)}");
            String upToken = getAuth().uploadToken(bucketName);
            Response response =  getUploadManager().put(inputStream, keyName, upToken, null, null);
            log.info("文件上传成功，keyName：{}, 结果：{}", keyName, response.toString());
            JSONObject obj = JSONUtil.parseObj(response.bodyString());
            return obj.getStr("key");
        } catch (QiniuException ex) {
            log.error("文件上传失败，keyName：{}", keyName, ex);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件上传失败");
        }
    }

    @Override
    public void download(String keyName, Consumer<InputStream> consumer) {
        URL url;
        try {
            url = new URL(fetchDownloadUrl(keyName, 3600L));
        } catch (MalformedURLException e) {
            log.error("文件下载失败，keyName：{}", keyName, e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件下载失败");
        }

        Resource resource = new UrlResource(url);
        if (resource.exists() || resource.isReadable()) {
            try (InputStream in = resource.getInputStream()) {
                consumer.accept(in);
            } catch(Exception e) {
                log.error("文件下载失败，keyName：{}", keyName, e);
                throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件下载失败");
            }
        }
    }

    @Override
    public String fetchDownloadUrl(String keyName, Long expire) {
        String result;
        try {
            String encodedFileName = URLEncoder.encode(keyName, "utf-8").replace("+", "%20");
            String publicUrl = String.format("%s/%s", domain, encodedFileName);
            if(null == expire) {
                result = publicUrl;
            } else {
                result = getAuth().privateDownloadUrl(publicUrl, expire);
            }
        } catch (Exception ex) {
            log.error("获取文件下载路径失败，keyName：{}", keyName, ex);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "获取文件下载路径失败");
        }
        return result;
    }

    @Override
    public void batchDelete(List<String> keyNames) {
        if (CollectionUtils.isEmpty(keyNames)) {
            return;
        }
        try {
            BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
            batchOperations.addDeleteOp(bucketName, keyNames.toArray(new String[0]));
            Response response = getBucketManager().batch(batchOperations);
            BatchStatus[] batchStatusList = response.jsonToObject(BatchStatus[].class);
            log.info("文件批量删除成功，keyNames：{}，结果：{}", keyNames, JSONUtil.toJsonStr(batchStatusList));
        } catch (QiniuException e) {
            log.error("文件批量删除失败，keyNames：{}", keyNames, e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件批量删除失败");
        }
    }
}
